package com.xuan.config;

import com.alibaba.fastjson.JSONObject;
import com.xuan.converter.MyAccountAuthentication;
import com.xuan.converter.MyAuthenticationConverter;
import com.xuan.converter.MyReactiveAuthorizationManager;
import io.netty.buffer.UnpooledByteBufAllocator;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.ReactiveAuthenticationManagerAdapter;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationEntryPoint;
import org.springframework.web.server.WebFilter;
import reactor.core.publisher.Flux;

import java.io.UnsupportedEncodingException;
import java.util.Iterator;

@EnableWebFluxSecurity
public class SecurityConfig {


    //security的鉴权排除的url列表 白名单
    private static final String[] excludedAuthPages = {
            "/api/user/register/**",
            "/api/sms/sendSms/**",
            "/api/static/**",
            "/api/account/index",
            "/api/account/login/*/*",
            "/api/account/register",
            "/api/user/sendSms/*",
            "/api/account/reset",
            "/api/sms/sendSms/*",
            "/api/user/reset/password"
    };

    //security的权限路径
    private static final String[] openedPages = {
            "/api/**"
    };

    //OpenedPages开放的角色权限
    private static final String[] openedRole = {
            "User",
            "Manager",
            "Dev"
    };


    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        RedirectServerAuthenticationEntryPoint loginPoint = new RedirectServerAuthenticationEntryPoint("/api/account/index");

        //pathMatchers 白名单路径
        http.authorizeExchange().pathMatchers(excludedAuthPages).permitAll()

                //需要拦截的URL为/xinyue-server-a/account/authen  如果没有认证跳转到 loginPoint 设置好的地址
                .and().formLogin().loginPage("/api/account/authen").authenticationEntryPoint(loginPoint)


                .authenticationSuccessHandler((webFilterExchange,authentication)->{//认证成功之后返回给客户端的信息
                    JSONObject result = new JSONObject();
                    result.put("code", 0);
                    return webFilterExchange.getExchange().getResponse().writeWith(Flux.create(sink -> {
                        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
                        try {
                            DataBuffer dataBuffer= nettyDataBufferFactory.wrap(result.toJSONString().getBytes("utf8"));
                            sink.next(dataBuffer);
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        sink.complete();
                    }));
                })

                //认证过后可以访问的位置                                                                指定角色可以访问
                .and().authorizeExchange().pathMatchers(openedPages).access(new MyReactiveAuthorizationManager("Admin", openedRole))

                //认证成功后才可跳转
                .and().authorizeExchange().anyExchange().authenticated()

                //停止攻击重定向
                .and().csrf().disable();

        SecurityWebFilterChain chain = http.build();
        Iterator<WebFilter> weIterable = chain.getWebFilters().toIterable().iterator();
        while(weIterable.hasNext()) {
            WebFilter f = weIterable.next();
            if(f instanceof AuthenticationWebFilter) {
                AuthenticationWebFilter webFilter = (AuthenticationWebFilter) f;
                //将自定义的AuthenticationConverter添加到过滤器中
                webFilter.setServerAuthenticationConverter(new MyAuthenticationConverter());
            }
        }
        return chain;
    }
    @Bean
    public ReactiveAuthenticationManager reactiveAuthenticationManager() {
        return new ReactiveAuthenticationManagerAdapter((authentication)->{
            if(authentication instanceof MyAccountAuthentication) {
                MyAccountAuthentication gmAccountAuthentication = (MyAccountAuthentication) authentication;
                if(gmAccountAuthentication.getPrincipal() != null) {
                    authentication.setAuthenticated(true);
                    return authentication;
                } else {
                    return authentication;
                }
            } else {
                return authentication;
            }
        });
    }
}
